package com.fy.opengltest.renderPolygn;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.opengl.GLES20;
import android.opengl.GLSurfaceView;
import android.opengl.Matrix;

import com.fy.opengltest.AbsRenderer;
import com.fy.opengltest.IChange;
import com.fy.opengltest.R;
import com.fy.opengltest.ShaderUtils;
import com.fy.opengltest.renderPicture.TextureHelper;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.ShortBuffer;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

/**
 * Created by yao.fu on 17-1-23.
 */
public class GLRendererFishCilibration extends AbsRenderer{

    private Uri uri;
    private Context context;
    private int programId;

    private int textureId;

    private FloatBuffer vertexBuffer;
    private ShortBuffer indexBuffer;
    private FloatBuffer textureVertexBuffer;

    private float dx = 0f;
    private float dy = 0f;

    private float[] vertexData = {
            -1f, -1f, 0f,
            1f, -1f, 0f,
            1f, 1f, 0f,
            -1f, 1f, 0f,
    };

    private final short[] indexData = {
            0, 1, 2,
            0, 2, 3,
            2, 1, 0,
            3, 2, 0
    };

    private float[] textureVertexData = {
            0f + dx, 0f + dy,
            1f + dx, 0f + dy,
            1f + dx, 1f + dy,
            0f + dx, 1f + dy
    };

    private float mParam_a = 1.0f;
    private float mParam_b = 1.0f;
    private float mParam_fx = 1.0f;
    private float mParam_fy = 1.0f;
    private float mParam_scale = 1.5f;
    private float mParam_x = 0f;
    private float mParam_y = 0f;

    private int uMatrixHandle;
    private int aVertexPosition;
    private int aTextureCoord;
    private int uSampler;
    private int uLensS;
    private int uLensF;
    private int uFov;

    private float[] mParam_lensS = new float[3];

    private float[] mParam_lensF = new float[2];

    private float[] mParam_fovs = new float[2];

    private final float[] projectionMatrix = new float[16];


    public GLRendererFishCilibration(Context context) {
        this.context = context;
    }

    public GLRendererFishCilibration(Context context, Uri uri) {
        this.context = context;
        this.uri = uri;
    }

    @Override
    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
        String vertexShader = ShaderUtils.readRawTextFile(context, R.raw.gl_vertex);
        String fragmentShader = ShaderUtils.readRawTextFile(context, R.raw.gl_fragment);
        programId = ShaderUtils.createProgram(vertexShader, fragmentShader);

        aVertexPosition = GLES20.glGetAttribLocation(programId, "aVertexPosition");
        aTextureCoord = GLES20.glGetAttribLocation(programId, "aTextureCoord");
        uMatrixHandle = GLES20.glGetUniformLocation(programId, "uMatrix");
        uSampler = GLES20.glGetUniformLocation(programId, "uSampler");
        uLensS = GLES20.glGetUniformLocation(programId, "uLensS");
        uLensF = GLES20.glGetUniformLocation(programId, "uLensF");
        uFov = GLES20.glGetUniformLocation(programId, "uFov");

        if (null != uri)
            textureId = TextureHelper.loadTexture(context, uri);
        else
            textureId = TextureHelper.loadTexture(context, R.raw.dome190_24402400);//R.raw.demo_pic);

        vertexBuffer = ByteBuffer.allocateDirect(vertexData.length * 4)
                .order(ByteOrder.nativeOrder())
                .asFloatBuffer()
                .put(vertexData);
        vertexBuffer.position(0);

        indexBuffer = ByteBuffer.allocateDirect(indexData.length * 2)
                .order(ByteOrder.nativeOrder())
                .asShortBuffer()
                .put(indexData);
        indexBuffer.position(0);

        textureVertexBuffer = ByteBuffer.allocateDirect(textureVertexData.length * 4)
                .order(ByteOrder.nativeOrder())
                .asFloatBuffer()
                .put(textureVertexData);
        textureVertexBuffer.position(0);
    }

    @Override
    public void onSurfaceChanged(GL10 gl, int width, int height) {
        if (null != uri) {
            Bitmap bmp = TextureHelper.getBitmap(context, uri);
            if (null != bmp) {
                updateProjection(bmp.getWidth(), bmp.getHeight(), width, height);
            }
        } else {
            updateProjection(1, 1, width, height);
        }
    }

    @Override
    public void onDrawFrame(GL10 gl) {

        //GLES20.glViewport(0, 0, screenWidth, screenHeight);

        GLES20.glClear(GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);
        GLES20.glUseProgram(programId);

        GLES20.glUniformMatrix4fv(uMatrixHandle, 1, false, projectionMatrix, 0);

        GLES20.glEnableVertexAttribArray(aVertexPosition);
        GLES20.glVertexAttribPointer(aVertexPosition, 3, GLES20.GL_FLOAT, false, 12, vertexBuffer);

        //GLES20.glEnableVertexAttribArray(aTextureCoord);
        //GLES20.glVertexAttribPointer(aTextureCoord, 2, GLES20.GL_FLOAT, false, 8, textureVertexBuffer);

        GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId);
        GLES20.glUniform1i(uSampler, 0);

        mParam_lensS[0] = mParam_a;
        mParam_lensS[1] = mParam_b;
        mParam_lensS[2] = mParam_scale;
        GLES20.glUniform3fv(uLensS, 1, mParam_lensS, 0);

        mParam_lensF[0] = mParam_fx;
        mParam_lensF[1] = mParam_fy;
        GLES20.glUniform2fv(uLensF, 1, mParam_lensF, 0);

        mParam_fovs[0] = mParam_x;
        mParam_fovs[1] = mParam_y;
        GLES20.glUniform2fv(uFov, 1, mParam_fovs, 0);

        GLES20.glDrawElements(GLES20.GL_TRIANGLES, indexData.length, GLES20.GL_UNSIGNED_SHORT, indexBuffer);

    }

    public float getmParam_a() {
        return mParam_a;
    }

    public float getmParam_b() {
        return mParam_b;
    }

    public float getmParam_fx() {
        return mParam_fx;
    }

    public float getmParam_fy() {
        return mParam_fy;
    }

    public float getmParam_scale() {
        return mParam_scale;
    }

    public float getmParam_x() {
        return mParam_x;
    }

    public float getmParam_y() {
        return mParam_y;
    }

    public void setFxF(float f){
        mParam_fx = f;
    }

    public void setFyF(float f){
        mParam_fy = f;
    }

    public void setAF(float a){
        mParam_a = a;
    }

    public void setBF(float b){
        mParam_b = b;
    }

    public void setScaleF(float s){
        mParam_scale = s;
    }

    public void setXF(float x){
        mParam_x = x;
    }

    public void setYF(float y){
        mParam_y = y;
    }

    private void updateProjection(float videoWidth, float videoHeight, int screenWidth, int screenHeight) {
        float screenRatio = (float) screenWidth / screenHeight;
        float videoRatio = (float) videoWidth / videoHeight;
        if (videoRatio > screenRatio) {
            Matrix.orthoM(projectionMatrix, 0, -1f, 1f, -videoRatio / screenRatio, videoRatio / screenRatio, -1f, 1f);
        } else
            Matrix.orthoM(projectionMatrix, 0, -screenRatio / videoRatio, screenRatio / videoRatio, -1f, 1f, -1f, 1f);
    }

    @Override
    public void onChange(int indentify, int index, float value) {
        switch (index) {
            case R.id.seekBarFx:
                setFxF(value);
                break;

            case  R.id.seekBarFy:
                setFyF(value);
                break;

            case R.id.seekBar1:
                setAF(value);
                break;

            case R.id.seekBar2:
                setBF(value);
                break;

            case R.id.seekBar3:
                setScaleF(value);
                break;

            case R.id.seekBar4:
                setXF(value);
                break;

            case R.id.seekBar5:
                setYF(value);
                break;
        }
    }

    @Override
    public String getTitle(int indentify, int index) {
        String value = "Unkown";
        switch (index) {
            case R.id.seekBarFx:
                value = "Fx:";
                break;

            case  R.id.seekBarFy:
                value = "Fy:";
                break;

            case R.id.seekBar1:
                value = "A:";
                break;

            case R.id.seekBar2:
                value = "B:";
                break;

            case R.id.seekBar3:
                value = "Scale:";
                break;

            case R.id.seekBar4:
                value = "X:";
                break;

            case R.id.seekBar5:
                value = "Y:";
                break;
        }
        return value;
    }

    @Override
    public float getValue(int indentify, int index) {
        float value = 0;
        switch (index) {
            case R.id.seekBarFx:
                value = getmParam_fx();
                break;

            case  R.id.seekBarFy:
                value = getmParam_fy();
                break;

            case R.id.seekBar1:
                value = getmParam_a();
                break;

            case R.id.seekBar2:
                value = getmParam_b();
                break;

            case R.id.seekBar3:
                value = getmParam_scale();
                break;

            case R.id.seekBar4:
                value = getmParam_x();
                break;

            case R.id.seekBar5:
                value = getmParam_y();
                break;
        }
        return value;
    }
}
